Interactive maps on Leaflet¶
Whenever you go into a website that has some kind of interactive map, it is quite probable that you are wittnessing a map that has been made with a JavaScipt library called Leaflet (the other popular one that you might have wittnessed is called OpenLayers.
There is also a Python module called Folium that makes it possible visualize data that’s been manipulated in Python on an interactive Leaflet map.
Creating a simple interactive web-map¶
Let’s first see how we can do a simple interactive web-map without any data on it. We just visualize OpenStreetMap on a specific location of the a world.
- First thing that we need to do is to create a Map instance. There are few parameters that we can use to adjust how in our Map instance that will affect how the background map will look like.
- See documentation of class folium.folium.Map() for all avaiable options.
In [44]:
import folium
# Create a Map instance
m = folium.Map(location=[60.25, 24.8],
zoom_start=10, control_scale=True)
The first parameter location takes a pair of lat, lon values as list
as an input which will determine where the map will be positioned when
user opens up the map. zoom_start -parameter adjusts the default
zoom-level for the map (the higher the number the closer the zoom is).
control_scale defines if map should have a scalebar or not.
- Let’s see what our map looks like:
In [45]:
m
Out[45]:
- We can also save the map already now
- Let’s save the map as a html file
base_map.html:
In [46]:
outfp = "base_map.html"
m.save(outfp)
Navigate to the location where you saved the html file and open it in a web browser (preferably Google Chrome) to see the output.
- Let’s change the basemap style to
Stamen Tonerand change the location of our map slightly. Thetiles-parameter is used for changing the background map provider and map style (see the documentation for all possible ones).
In [47]:
# Let's change the basemap style to 'Stamen Toner'
m = folium.Map(location=[40.730610, -73.935242], tiles='Stamen Toner',
zoom_start=12, control_scale=True, prefer_canvas=True)
m
Out[47]:
- let’s also save this map as a html file:
In [48]:
# Filepath to the output
outfp = "base_map2.html"
# Save the map
m.save(outfp)
Task¶
Let’s take a few moments and play around with the parameters. Save the map and see how those changes affect the look of the map.
Adding layers to the map¶
Adding layers to a web-map is fairly straightforward and similar procedure as with Bokeh and we can use familiar tools to handle the data, i.e. Geopandas. Our ultimate aim is to create a plot like this where population in Helsinki and the address points are plotted on top of a web-map:
Let’s first practice by adding the address points onto the Helsinki basemap: - read input points using Geopandas:
In [49]:
import geopandas as gpd
# File path
points_fp = r"dataE5/addresses.shp"
# Read the data
points = gpd.read_file(points_fp)
#Check input data
points.head()
Out[49]:
| address | id | geometry | |
|---|---|---|---|
| 0 | Kampinkuja 1, 00100 Helsinki, Finland | 1001 | POINT (24.9301701 60.1683731) |
| 1 | Kaivokatu 8, 00101 Helsinki, Finland | 1002 | POINT (24.9418933 60.1698665) |
| 2 | Hermanstads strandsväg 1, 00580 Helsingfors, F... | 1003 | POINT (24.9774004 60.18735880000001) |
| 3 | Itäväylä, 00900 Helsinki, Finland | 1004 | POINT (25.0919641 60.21448089999999) |
| 4 | Tyynenmerenkatu 9, 00220 Helsinki, Finland | 1005 | POINT (24.9214846 60.1565781) |
In [ ]:
In [ ]:
# Convert points to GeoJson
#points_gjson = folium.features.GeoJson(points.to_json())
points_gjson = folium.features.GeoJson(points)
In [ ]:
Now we have our population data stored in the ``pop_json`` variable as GeoJSON format which basically contains the
data as text in a similar way that it would be written in the ``.geojson`` -file.
- add the points onto the Helsinki basemap
In [50]:
# Create a Map instance
m = folium.Map(location=[60.25, 24.8], tiles = 'cartodbpositron', zoom_start=11, control_scale=True)
# Add points to the map instance
points_gjson.add_to(m)
# Alternative syntax for adding points to the map instance
#m.add_child(points_gjson)
#Show map
m
Out[50]:
Choroplet map¶
Next, let’s check how we can overlay a population map on top of a basemap using folium’s choropleth method. This method is able to read the geometries and attributes directly from a geodataframe. This example is modified from the Folium quicksart.
- First, read in the population grid:
In [51]:
# Filepaths
fp = "dataE5/Vaestotietoruudukko_2015.shp"
# Read Data
data = gpd.read_file(fp)
# Check the data
data.head()
Out[51]:
| INDEX | ASUKKAITA | ASVALJYYS | IKA0_9 | IKA10_19 | IKA20_29 | IKA30_39 | IKA40_49 | IKA50_59 | IKA60_69 | IKA70_79 | IKA_YLI80 | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 688 | 8 | 31.0 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | POLYGON ((25472499.99532626 6689749.005069185,... |
| 1 | 703 | 6 | 42.0 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | POLYGON ((25472499.99532626 6685998.998064222,... |
| 2 | 710 | 8 | 44.0 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | POLYGON ((25472499.99532626 6684249.004130407,... |
| 3 | 711 | 7 | 64.0 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | POLYGON ((25472499.99532626 6683999.004997005,... |
| 4 | 715 | 19 | 23.0 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | POLYGON ((25472499.99532626 6682998.998461431,... |
- re-project layer into WGS 84 (epsg: 4326)
- Modify columns:
In [52]:
# Re-project to WGS84
data = data.to_crs(epsg=4326)
# Check layer crs definition
print(data.crs)
# Make a selection (only data above 0 and below 1000)
data = data.loc[(data['ASUKKAITA'] > 0) & (data['ASUKKAITA'] <= 1000)]
# Create a Geo-id which is needed by the Folium (it needs to have a unique identifier for each row)
data['geoid'] = data.index.astype(str)
# Select only needed columns
data = data[['geoid', 'ASUKKAITA', 'geometry']]
# Convert to geojson (not needed for the simple coropleth map!)
#pop_json = data.to_json()
#check data
data.head()
{'init': 'epsg:4326', 'no_defs': True}
Out[52]:
| geoid | ASUKKAITA | geometry | |
|---|---|---|---|
| 0 | 0 | 8 | POLYGON ((24.50236241370834 60.31927864851716,... |
| 1 | 1 | 6 | POLYGON ((24.50287385337343 60.28562263749414,... |
| 2 | 2 | 8 | POLYGON ((24.50311210582754 60.26991652312412,... |
| 3 | 3 | 7 | POLYGON ((24.50314612020954 60.26767278939882,... |
| 4 | 4 | 19 | POLYGON ((24.50328212493893 60.25869775697638,... |
In [53]:
# Create a Map instance
m = folium.Map(location=[60.25, 24.8], tiles = 'cartodbpositron', zoom_start=10, control_scale=True)
# Plot a choropleth map
# Notice: 'geoid' column that we created earlier needs to be assigned always as the first column
m.choropleth(
geo_data=data,
name='choropleth',
data=data,
columns=['geoid', 'ASUKKAITA'],
key_on='feature.id',
fill_color='YlOrRd',
fill_opacity=0.7,
line_opacity=0.2,
line_color='white',
line_weight=0,
highlight=False,
smooth_factor=1.0,
#threshold_scale=[100, 250, 500, 1000, 2000],
legend_name= 'Population in Helsinki')
#Show map
m
Out[53]:
Clustered point map¶
In [ ]: